<template>
    <div class="wrapper">
        <div class="map" id="map"></div>
    </div>
</template>

<script lang="ts" setup>
import { Feature, Map, MapBrowserEvent, View } from 'ol';
import TileLayer from 'ol/layer/Tile';
import VectorLayer from 'ol/layer/Vector';
import { XYZ } from 'ol/source';
import VectorSource from 'ol/source/Vector';
import { Fill, Icon, Stroke, Style } from 'ol/style';
import { onMounted, ref } from 'vue';
import { click } from 'ol/events/condition';
import { nanoid } from 'nanoid';
import { SelectEvent } from 'ol/interaction/Select';
import { Circle, LineString, Point, Polygon, SimpleGeometry } from 'ol/geom';
import { Snap, Select } from 'ol/interaction';
import { Coordinate } from 'ol/coordinate';

const map = ref();
const source = ref();
const layer = ref();
const uid = ref(nanoid());
const select = ref();
const snap = ref();
const style = new Style({
    fill: new Fill({ color: [255, 128, 0, 0.5] }),
    stroke: new Stroke({ color: [255, 128, 0, 0.5], width: 4 }),
    image: new Icon({
        src: new URL('../../assets/map-point.png', import.meta.url).href,
        width: 32,
        height: 32
    })
});
const selectStyle = new Style({
    fill: new Fill({ color: [0, 128, 255, 0.5] }),
    stroke: new Stroke({ color: [0, 128, 255, 0.5], width: 4 }),
    image: new Icon({
        src: new URL('../../assets/map-point-active.png', import.meta.url).href,
        width: 32,
        height: 32
    })
});

onMounted(() => {
    map.value = new Map({
        target: 'map',
        view: new View({
            center: [116.4, 39.9],
            zoom: 12,
            projection: 'EPSG:4326'
        }),
        layers: [
            new TileLayer({
                source: new XYZ({
                    url: `http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7`
                })
            })
        ]
    });

    source.value = new VectorSource({ wrapX: true });
    layer.value = new VectorLayer({
        source: source.value,
        style
    });
    layer.value.set('uid', uid.value);
    map.value.addLayer(layer.value);

    select.value = new Select({
        style: selectStyle,
        condition: function (mapBrowserEvent: MapBrowserEvent) {
            return click(mapBrowserEvent);
        },
        layers: (layer) => {
            return layer.get('uid') === uid.value;
        }
    });
    select.value.on('select', (e: SelectEvent) => {
        console.log(e);
        if (e.selected.length > 0) {
            e.selected.forEach((feature: Feature) => {
                const coordinates = (
                    feature.getGeometry() as SimpleGeometry
                ).getFlatCoordinates();
                console.log('select=', coordinates);
            });
        }
    });
    map.value.addInteraction(select.value);

    snap.value = new Snap({
        source: source.value
    });
    map.value.addInteraction(snap.value);

    addFeature([116.37829804066813, 39.866640485893114], 'Point');

    addFeature(
        [116.19846954345705, 39.93218650817871],
        'Circle',
        0.035012188432574476
    );

    addFeature(
        [
            [116.28979339599611, 39.8326229095459],
            [116.32137908935549, 39.866611862182616],
            [116.3601745605469, 39.832966211345045],
            [116.40308990478518, 39.863865280151366],
            [116.44428863525393, 39.832966211345045],
            [116.46420135498049, 39.86832847595215]
        ],
        'LineString'
    );

    addFeature(
        [
            [
                [116.43639221191408, 39.892361058248206],
                [116.54488220214846, 39.892361058248206],
                [116.54488220214846, 39.93493309020996],
                [116.43639221191408, 39.93493309020996],
                [116.43639221191408, 39.892361058248206]
            ]
        ],
        'Polygon'
    );

    addFeature(
        [
            [
                [116.2836135864258, 39.87450828552246],
                [116.30421295166018, 39.93767966700252],
                [116.36463777730243, 39.94797934961971],
                [116.38283386230471, 39.91227378845215],
                [116.36704101562502, 39.87828483581543],
                [116.2836135864258, 39.87450828552246]
            ]
        ],
        'Polygon'
    );
});

function addFeature(
    data: number[] | number[][] | number[][][],
    type: 'Point' | 'LineString' | 'Polygon' | 'Circle',
    radius?: number
) {
    const feature = new Feature({
        type: type,
        geometry: getGeometry(data, type, radius)
    });
    source.value.addFeature(feature);
}

function getGeometry(
    data: number[] | number[][] | number[][][],
    type: 'Point' | 'LineString' | 'Polygon' | 'Circle',
    radius?: number
) {
    if (type === 'Point') {
        return new Point(data as Coordinate);
    } else if (type === 'LineString') {
        return new LineString(data as Coordinate[]);
    } else if (type === 'Circle') {
        return new Circle(data as number[], radius);
    } else if (type === 'Polygon') {
        return new Polygon(data as Coordinate[][]);
    }
    throw new Error('No Type');
}
</script>

<style lang="scss" scoped>
.wrapper {
    height: 100%;
    .map {
        height: 100%;
    }
}
</style>